/**
 * Copyright (c) 2018 人人开源 All rights reserved.
 * <p>
 *

 * <p>
 * 版权所有，侵权必究！
 */

package io.admin.modules.oss.controller;

import cn.hutool.core.io.file.FileNameUtil;
import com.google.common.io.ByteStreams;
import io.admin.common.annotation.LogOperation;
import io.admin.common.constant.Constant;
import io.admin.common.exception.ErrorCode;
import io.admin.common.page.PageData;
import io.admin.common.utils.BaiduMapImageExporter;
import io.admin.common.utils.ExcelUtils;
import io.admin.common.utils.FileUtil;
import io.admin.common.utils.JsonUtils;
import io.admin.common.utils.Result;
import io.admin.common.utils.StringUtils;
import io.admin.common.validator.ValidatorUtils;
import io.admin.common.validator.group.AliyunGroup;
import io.admin.common.validator.group.QcloudGroup;
import io.admin.common.validator.group.QiniuGroup;
import io.admin.modules.oss.cloud.CloudStorageConfig;
import io.admin.modules.oss.cloud.OSSFactory;
import io.admin.modules.oss.entity.SysOssEntity;
import io.admin.modules.oss.service.SysOssService;
import io.admin.modules.sys.dto.FileUrlDTO;
import io.admin.modules.sys.service.FileUrlService;
import io.admin.modules.sys.service.SysParamsService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
import org.apache.http.HttpStatus;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLDecoder;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;

/**
 * 文件上传
 *
 * @author Mark sunlightcs@gmail.com
 */
@RestController
@RequestMapping("sys/oss")
@Api(tags = "文件上传")
@AllArgsConstructor
@Slf4j
public class SysOssController {
    private final SysOssService sysOssService;
    private final SysParamsService sysParamsService;

    private final static String KEY = Constant.CLOUD_STORAGE_CONFIG_KEY;
    private final  static String ADDRESS_FILE = ExcelUtils.ADDRESS_FILE;
   // private final  static String ADDRESS_FILE = ExcelCopyUrils.ADDRESS_Mb_FILE;
    @Autowired
    private FileUrlService fileUrlService;

    @GetMapping("page")
    @ApiOperation(value = "分页")
    @RequiresPermissions("sys:oss:all")
    public Result<PageData<SysOssEntity>> page(@ApiIgnore @RequestParam Map<String, Object> params) {
        PageData<SysOssEntity> page = sysOssService.page(params);

        return new Result<PageData<SysOssEntity>>().ok(page);
    }

    @GetMapping("info")
    @ApiOperation(value = "云存储配置信息")
    @RequiresPermissions("sys:oss:all")
    public Result<CloudStorageConfig> info() {
        CloudStorageConfig config = sysParamsService.getValueObject(KEY, CloudStorageConfig.class);

        return new Result<CloudStorageConfig>().ok(config);
    }

    @PostMapping
    @ApiOperation(value = "保存云存储配置信息")
    @LogOperation("保存云存储配置信息")
    @RequiresPermissions("sys:oss:all")
    public Result saveConfig(@RequestBody CloudStorageConfig config) {
        //校验类型
        ValidatorUtils.validateEntity(config);

        if (config.getType() == Constant.CloudService.QINIU.getValue()) {
            //校验七牛数据
            ValidatorUtils.validateEntity(config, QiniuGroup.class);
        } else if (config.getType() == Constant.CloudService.ALIYUN.getValue()) {
            //校验阿里云数据
            ValidatorUtils.validateEntity(config, AliyunGroup.class);
        } else if (config.getType() == Constant.CloudService.QCLOUD.getValue()) {
            //校验腾讯云数据
            ValidatorUtils.validateEntity(config, QcloudGroup.class);
        }

        sysParamsService.updateValueByCode(KEY, JsonUtils.toJsonString(config));

        return new Result();
    }

    @PostMapping("upload")
    @ApiOperation(value = "上传文件")
    public Result<Map<String, Object>> upload(@RequestParam("file") MultipartFile file) throws Exception {
        if (file.isEmpty()) {
            return new Result<Map<String, Object>>().error(ErrorCode.UPLOAD_FILE_EMPTY);
        }
        //上传文件
        String suffix = FileNameUtil.getSuffix(file.getOriginalFilename());
        String url = OSSFactory.build().uploadSuffix(file.getBytes(), suffix);
        //保存文件信息
        SysOssEntity ossEntity = new SysOssEntity();
        ossEntity.setUrl(url);
        ossEntity.setCreateDate(new Date());
        sysOssService.insert(ossEntity);

        Map<String, Object> data = new HashMap<>(1);
        data.put("src", url);

        return new Result<Map<String, Object>>().ok(data);
    }

    @DeleteMapping
    @ApiOperation(value = "删除")
    @LogOperation("删除")
    @RequiresPermissions("sys:oss:all")
    public Result delete(@RequestBody Long[] ids) {
        sysOssService.deleteBatchIds(Arrays.asList(ids));

        return new Result();
    }


    @PostMapping("uploadByLocal")
    @ApiOperation(value = "上传文件")
    public Result<Map<String, Object>> uploadByLocal(@RequestParam("file") MultipartFile file) throws Exception {
        String url= "";
        if (file.isEmpty()) {
            return new Result<Map<String, Object>>().error(ErrorCode.UPLOAD_FILE_EMPTY);
        }
        //上传文件
        String suffix = FileNameUtil.getSuffix(file.getOriginalFilename());
        try {
            // 获取文件名
            String ext = FileUtil.checkFileSuffix(file.getInputStream(), file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".") + 1).toLowerCase());
           //不合法文件类型暴力返回空
            if (StringUtils.isEmpty(ext)) {
                log.info("非法文件类型");
                return new Result<Map<String, Object>>().error(10001,"无效文件");
            }
            String uuid = UUID.randomUUID().toString().replaceAll("-", "");
            String fileName = uuid + "." + ext;
            File fileIs = new File(ADDRESS_FILE);
            if(!fileIs.exists()){
                boolean created = fileIs.mkdir();
            }
            // 获取文件的字节
            byte[] bytes = file.getBytes();
            //文件路径
            String fileNamePath = ADDRESS_FILE+fileName;
            // 使用文件名在服务器端创建文件
            java.nio.file.Path path = java.nio.file.Paths.get(fileNamePath);
            // 写入文件到服务器的指定目录
            java.nio.file.Files.write(path, bytes);
            FileUrlDTO fileUrlDTO =new FileUrlDTO();
            fileUrlDTO.setId(generateRandomLongId());
            fileUrlDTO.setUrl(fileName);
            fileUrlService.save(fileUrlDTO);
            Map<String,Object> map = new HashMap<>();
            map.put("url", fileName);
            map.put("fileId", fileUrlDTO.getId());
            return new Result<Map<String, Object>>().ok(map);

        } catch (Exception e) {
            e.printStackTrace();
            return new Result<Map<String, Object>>().error(10001,"文件上传失败");
        }
    }

    @RequestMapping("uploadLocalByUrl")
    @ApiOperation(value = "文件上传url")
    public Result<Map<String, Object>> downloadLocalByUrl(HttpServletRequest request, HttpServletResponse response) throws Exception {
        //根据拿到的数据开始下载
        String fileName =request.getParameter("fileName");
        String url =request.getParameter("url");
        url = URLDecoder.decode(url, "UTF-8");
        BaiduMapImageExporter.extracted(fileName,url);
        FileUrlDTO fileUrlDTO =new FileUrlDTO();
        fileUrlDTO.setId(generateRandomLongId());
        fileUrlDTO.setUrl(fileName);
        fileUrlService.save(fileUrlDTO);
        Map<String,Object> map = new HashMap<>();
        map.put("url", fileName);
        map.put("fileId", fileUrlDTO.getId());
        return new Result<Map<String, Object>>().ok(map);
    }
    @RequestMapping("downloadLocal")
    @ApiOperation(value = "文件下载")
    public void downloadLocal(HttpServletRequest request, HttpServletResponse response) throws Exception {
        //根据拿到的数据开始下载
        String name =request.getParameter("name");
        File file = new File(ADDRESS_FILE+request.getParameter("name"));
        FileInputStream in = null;
        OutputStream out = null;
        if (file.exists()) {
            log.info("查询到本地的file文件");
            try {
                in = new FileInputStream(file);
                out = response.getOutputStream();
                //刷新Response的缓存
                response.setCharacterEncoding("UTF-8");
                // 设定输出文件头
                // 设置文件大小
                response.setHeader("Content-Length",String.valueOf(file.length()) );
                response.setHeader("Content-disposition", "attachment; filename=" + file.getName());
                ByteStreams.copy(in, out);
                response.setStatus(HttpStatus.SC_OK);
            } catch (IOException e) {
                log.error("", e);
            } finally {
                if (null != in) {
                    in.close();
                }
                if (null != out) {
                    out.close();
                }
            }
        }
    }


    @RequestMapping("downloadLocalByHalf")
    @ApiOperation(value = "文件下载")
    public void downloadLocalByHalf(HttpServletRequest request, HttpServletResponse response) throws Exception {
        //根据拿到的数据开始下载
        String name =request.getParameter("name");
        File file = new File(ADDRESS_FILE+request.getParameter("name"));
        OutputStream out  = response.getOutputStream();
        if (file.exists()) {
            log.info("查询到本地的file文件");
            try {
                if (!FileUtil.checkFileSize(file)) {
                    return;
                }
                //刷新Response的缓存
                response.setCharacterEncoding("UTF-8");
                Thumbnails.of(file)
                        .scale(0.35) // 保持原始尺寸
                        .outputQuality(1.0) // 设置图片质量，范围为0.0到1.0
                        .toOutputStream(out);
                // 设定输出文件头
                response.setHeader("Content-disposition", "attachment; filename=" + file.getName());
                response.setStatus(HttpStatus.SC_OK);
            } catch (IOException e) {
                log.error("", e);
            } finally {
                if (null != out) {
                    out.close();
                }
            }
        }
    }
    public static long generateRandomLongId() {
        return ThreadLocalRandom.current().nextLong();
    }
}